`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/05/14 18:58:43
// Design Name: 
// Module Name: CPU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module CPU(

  //原始时钟信号和复位信号
  input clk,
  input rst,
  //来自开发板开关的输入
  input[23:0] switchInput,
  //用24个LED灯进行输出
  output[23:0] ledOutput
    );

  //利用分频器把原始时钟信号转换为CPU的时钟信号
  parameter period = 50000000;
  reg clock;
  reg[31:0] cnt;
  reg[2:0] scan_cnt;
  
  always @(posedge clk or posedge rst)
  begin
    if(rst) begin
        cnt <= 0;
        clock <= 0;
    end
    else begin
        if(cnt == (period >> 1) - 1)
        begin
            clock <= ~clock;
            cnt <= 0;
        end
        else
            cnt <= cnt + 1;
    end
  end

  //接下来，定义不同的wire信号，用于连线
  //31位指令
  wire[31:0] Instruction;
  //由ALU计算出来的地址结果
  wire[31:0] Addr_Result;
  //这个是用于beq,bne计算用的基址
  wire[31:0] PC_plus_4;
  //从decoder中读出来的操作数1
  wire[31:0] Read_data_1;
  //从decoder中读出来的操作数2
  wire[31:0] Read_data_2;
  //Branch控制信号
  wire Branch;
  //bne控制信号
  wire nBranch;
  //jal控制信号
  wire Jal;
  //j控制信号
  wire Jmp;
  //jr控制信号
  wire Jr;
  //bne,beq用于判断的信号
  wire Zero;
  //用于jal指令的link地址
  wire[31:0] link_addr;
  //我要写到寄存器组中的数
  wire[31:0] r_wdata;
  //是否有向寄存器组中写数据的权限
  wire RegWrite;
  //写入寄存器的编号是rd还是rt
  wire RegDST;
  //已经进行扩展的立即数
  wire[31:0] imme_extend;
  //ALU的第二个操作数的来源
  wire ALUSrc;
  //表示要从内存或者IO向寄存器组中写入数据
  wire MemorIOtoReg;
  //开启读取内存的权限
  wire MemRead;
  //是否有向内存中写入数据的权限
  wire MemWrite;
  //是不是要从IO中读取数据
  wire IORead;
  //是不是要把数据从IO写出去
  wire IOWrite;
  //判断是不是立即数参与运算的I型指令
  wire I_format;
  //是不是移位指令
  wire Sftmd;
  wire[1:0] ALUOp;
  //ALU算术逻辑运算的结果
  wire[31:0] ALU_Result;
  //从数据内存中读取的数据
  wire[31:0] data_read_from_dm;
  //要从数据内存中读取数据所用的地址
  wire[31:0] address;
  //要写入内存的数
  wire[31:0] write_data;
  //从IO中读取的数
  wire[31:0] ioread_data;
  //开关片选信号
  wire switchcs;
  //从开关中读取的数
  wire[15:0] switch_read_data;
  //led灯片选信号
  wire ledcs;









  //例化部分
  Ifetc32 ifetc32(
    .Instruction(Instruction),//从Ifetc32中取出指令
    .Addr_result(Addr_Result),//ALU计算的地址，我要从这里面取出来
    .branch_base_addr(PC_plus_4),//让取指令部分输出bne,beq所要用的基址
    .Read_data_1(Read_data_1),//这个主要用于jr指令
    .Branch(Branch),//读取beq控制信号，方便更新PC
    .nBranch(nBranch),//同上
    .Jal(Jal),//方便更新PC
    .Jmp(Jmp),//方便更新PC
    .Jr(Jr),//方便更新PC
    .Zero(Zero),//我要知道Zero这个信号到底是怎么样，执行还是不执行beq,bne
    .link_addr(link_addr),//如果是jal指令输出要link的地址
    .clock(clock),
    .reset(rst)


  );

  Idecode32 idecoder32(
    .Instruction(Instruction), //我要给这个指令解码
    .read_data_1(Read_data_1),//从decoder中读取出第一个操作数
    .Jal(Jal),//要给寄存器$ra写进保存的地址
    .opcplus4(link_addr),//用于jal指令，把这个地址写进寄存器组中
    .read_data_2(Read_data_2),//从idecoder中读取第二个操作数
    .read_data(r_wdata),//从内存或者IO读进来，要写到寄存器组中的数
    .RegWrite(RegWrite),//是否开启向寄存器组中写数据的权限
    .RegDst(RegDST),//写入寄存器来源
    .imme_extend(imme_extend),//扩展立即数
    .MemtoReg(MemorIOtoReg),//标识我要从IO或者内存或者ALU向寄存器中写入数据
    .ALU_result(ALU_Result),
    .clock(clock),
    .reset(rst)
    

  );

  control32 control(
    .Branch(Branch),//Branch控制信号
    .nBranch(nBranch),//nBranch控制信号
    .Jal(Jal),//Jal控制信号
    .Jmp(Jmp),//生成jmp信号
    .Jr(Jr),//生成Jr控制信号
    .RegWrite(RegWrite),//是不是有向寄存器组中写数据的权限
    .RegDST(RegDST),//写入寄存器来源
    .ALUSrc(ALUSrc),//ALU第二个操作数的来源
    .MemorIOtoReg(MemorIOtoReg),//标识要从内存或者IO向寄存器组中写入数据
    .MemRead(MemRead),//开启读取内存的权限
    .MemWrite(MemWrite),//是否开启对内存写入数据的权限
    .IORead(IORead),//是不是要从IO中读取数据
    .IOWrite(IOWrite),//是不是要把数据通过IO写出去
    .I_format(I_format),//判断是不是立即数参与运算的I型指令
    .Sftmd(Sftmd),//判断是不是移位指令
    .ALUOp(ALUOp),
    .Alu_resultHigh(ALU_Result[31:10]),
    .Opcode(Instruction[31:26]),
    .Function_opcode(Instruction[5:0])
  );

  Executs32 executs(
    .opcode(Instruction[31:26]), //把指令的opcode取出来给ALU
    .Function_opcode(Instruction[5:0]),//指令的functioncode
    .Shamt(Instruction[10:6]), //指令中移位运算的数量
    .Addr_Result(Addr_Result),//由ALU计算出的地址的结果
    .PC_plus_4(PC_plus_4),//用来计算beq,bne跳转后的地址
    .Read_data_1(Read_data_1),//把第一个操作数给ALU进行运算
    .Jr(Jr),//貌似没用
    .Zero(Zero),//判断bne,beq是否相等
    .Read_data_2(Read_data_2),//读取第二个操作数
    .Imme_extend(imme_extend),//进行扩展的立即数
    .ALUSrc(ALUSrc),//ALU第二个操作数来源
    .I_format(I_format),//判断是不是立即数参与运算的I型指令
    .Sftmd(Sftmd),//判断是不是移位指令
    .ALUOp(ALUOp),
    .ALU_Result(ALU_Result)//ALU算术逻辑运算结果
    

  );

  dmemory32 memory(
    .Memwrite(MemWrite),//是否开启对内存写的权限
    .read_data(data_read_from_dm),
    .address(address),
    .write_data(write_data),
    .clock(clock)
  );

  MemOrIO memorio(
    .r_rdata(Read_data_2),//从寄存器中读出来的数，我要把它放到内存中或者用IO显示
    .r_wdata(r_wdata),//我要写到寄存器组中的数
    .mRead(MemRead),//是否开启读取内存的权限，表明向寄存器中写进去的数据来源于内存还是IO
    .mWrite(MemWrite),//表示我是不是有向内存中写数据的权限
    .ioRead(IORead),//是不是要从IO中读取数据
    .ioWrite(IOWrite),//是不是要把数据通过IO写出去
    .addr_in(ALU_Result),
    .m_rdata(data_read_from_dm),
    .addr_out(address),
    .write_data(write_data),
    .io_rdata(ioread_data),
    .SwitchCtrl(switchcs),
    .LEDCtrl(ledcs)
  );

  SwitchInput switchinput(
    .IORead(IORead),//是不是要从IO中读取数据
    .ioread_data(ioread_data),
    .switchcs(switchcs),
    .switch_data(switch_read_data),
    .rst(rst)
  );

  switchs switch
  (
    .switchaddr(address[1:0]),
    .switchread(IORead),
    .switchrdata(switch_read_data),
    .switchcs(switchcs),
    .switclk(clock),
    .switrst(rst),
    .switch_i(switchInput)

  );

  leds led(
    .ledaddr(address[1:0]),
    .ledwrite(IOWrite),
    .ledwdata(write_data[15:0]),
    .ledcs(ledcs),
    .led_clk(clock),
    .ledrst(rst),
    .ledout(ledOutput)
  );

  



endmodule
